#include "SmartQuery.h"

using namespace DatabaseModule;

QString SmartQuery::generateSelectCase() {
	if (fieldList.isEmpty()) {
		qDebug() << "Error in " << __FUNCTION__ << ". fieldList is empty";

		return "";
	}

	QString result = "";

	foreach (QString field, fieldList)
		result += field + ", ";

	result.truncate(result.size() - 2);

	return result;
}

QString SmartQuery::generateOrderCase() {
	if (orderList.isEmpty()) {
		qDebug() << "Notif in " << __FUNCTION__ << ". orderList is empty";

		return "";
	}

	QString result = "";

	foreach (QString orderBy, orderList)
		result += orderBy + ", ";

	result.truncate(result.size() - 2);

	return result;
}

void SmartQuery::parseTableList() {
	if (fieldList.isEmpty()) {
		qDebug() << "Error in " << __FUNCTION__ << ". fieldList is empty";
		tableList.clear();

		return;
	}

	tableList.clear();

	foreach (QString field, fieldList) {
		QString table = field.left(field.indexOf('.'));

		if (!tableList.contains(table))
			tableList.push_back(table);
	}

	foreach (StringPair pair, termList) {
		QString table = pair.first.left(pair.first.indexOf('.'));

		if (!tableList.contains(table))
			tableList.push_back(table);
	}

	int tableListSize = tableList.size();

	for (int i = 0; i <tableListSize; ++i)
		for (int j = i + 1; j < tableListSize; ++j) {
			QStringList imTables = getIntermediateTables(tableList.at(i), tableList.at(j));

			foreach (QString table, imTables)
				if (!tableList.contains(table))
					tableList.push_back(table);
		}	
}

QStringList SmartQuery::getIntermediateTables(const QString &source, const QString &destination) {
	QStringList result;

	if (dbWorker.use_count() == 0) {
		DatabaseWork *dbw = new DatabaseWork(dbName);
		dbWorker.reset(dbw);
	}

	if (source == destination) {
		qDebug() << "Warning in " << __FUNCTION__ << ". source == destination";

		return result;
	}

	QString query = "SELECT id FROM sys_links \
					WHERE source_table == \"%1\" \
					AND destination_table == \"%2\" \
					AND relations != \"\"";
	QSqlQuery resultQuery;

	if (!dbWorker->execSqlQuery(query.arg(source, destination), resultQuery))
		return result;

	if (resultQuery.first())
		return result;

	query = "SELECT via FROM sys_links \
			WHERE source_table == \"%1\" \
			AND destination_table == \"%2\" LIMIT 1";
	
	if (!dbWorker->execSqlQuery(query.arg(source, destination), resultQuery))
		return result;

	if (!resultQuery.first())
		return result;

	QSqlRecord rec = resultQuery.record();
	QString via = resultQuery.value(rec.indexOf("via")).toString();

	result = getIntermediateTables(source, via);

	result.push_back(via);

	return result;
}

QStringList SmartQuery::generateLinkTerms() {
	if (dbWorker.use_count() == 0) {
		DatabaseWork *dbw = new DatabaseWork(dbName);
		dbWorker.reset(dbw);
	}
	
	parseTableList();

	QStringList result;

	if (tableList.isEmpty()) {
		qDebug() << "Error in " << __FUNCTION__ << ". tableList is empty";

		return result;
	}

	QString query = "SELECT relations FROM sys_links \
					WHERE (source_table == \"%1\" \
					AND destination_table == \"%2\") \
					OR (source_table == \"%2\" \
					AND destination_table == \"%1\") \
					AND relations != \"\"";

	for (int i = 0; i < tableList.size(); ++i)
		for (int j = i + 1; j < tableList.size(); ++j) {
			QSqlQuery resultQuery;

			if (!dbWorker->execSqlQuery(query.arg(tableList.at(i), tableList.at(j)), resultQuery)) {
				result.clear();

				return result;
			}

			resultQuery.first();

			QSqlRecord rec = resultQuery.record();
			QString term = resultQuery.value(rec.indexOf("relations")).toString();

			if (!term.isEmpty())
				result.push_back(term);
		}

	return result;
}

QString SmartQuery::generateFromCase() {
	parseTableList();

	if (tableList.isEmpty()) {
		qDebug() << "Error in " << __FUNCTION__ << ". tableList is empty";

		return "";
	}

	QString result = "";

	foreach (QString table, tableList)
		result += table + ", ";

	result.truncate(result.size() - 2);

	return result;
}

QString SmartQuery::generateWhereCase() {
	QStringList linkTermList = generateLinkTerms();
	QString result = "";

	if (!linkTermList.isEmpty()) {
		result = '(';

		foreach (QString linkTerm, linkTermList)
			result += linkTerm + " AND ";

		result.truncate(result.size() - 5);

		result += ')';
	}

	if (!termList.isEmpty()) {
		if (result.size() == 0)
			result = '(';
		else
			result += " AND (";

		int i = 0;

		foreach (StringPair pair, termList) {
			if (i++)
				result += ' ' + pair.second + ' ';

			result += pair.first;
		}

		result += ')';
	}

	return result;
}

QString SmartQuery::generateSqlQuery() {
	QString selectCase	= generateSelectCase();
	qDebug() << selectCase;

	QString fromCase	= generateFromCase();
	qDebug() << fromCase;

	QString whereCase	= generateWhereCase();
	qDebug() << whereCase;

	QString orderCase	= generateOrderCase();
	qDebug() << orderCase;

	QString result = "";

	if (selectCase.isEmpty())
		return result;
	else
		result = "SELECT " + selectCase;

	if (fromCase.isEmpty())
		return result = "";
	else
		result += " FROM " + fromCase;

	if (!whereCase.isEmpty())
		result += " WHERE " + whereCase;

	if (!orderCase.isEmpty())
		result += " ORDER BY " + orderCase;

	return result;
}

QueryModelPtr SmartQuery::exec() {
	QueryModelPtr sqlModel;
	QString query = generateSqlQuery();

	if (dbWorker.use_count() == 0) {
		DatabaseWork *dbw = new DatabaseWork(dbName);
		dbWorker.reset(dbw);
	}

	sqlModel = dbWorker->getSqlModel(query);

	return sqlModel;
}